package event

// option 定义了用于配置 EventMgr 的函数类型
type option func(*EventMgr)

// SetEventMgrIDGenerator 设置 EventMgr 的 ID 生成器
func SetEventMgrIDGenerator(f IDGeneratorFunc) option {
	return func(mgr *EventMgr) {
		mgr.getID = f
	}
}

/*
事件管理器
注册的事件不分先后，不依赖于注册的顺序，随机顺序触发
*/
// EventMgr 负责事件的注册、触发与管理
type EventMgr struct {
	EventList map[EventTypeEnum]map[uint64]OnEventChanged //事件列表

	getID IDGeneratorFunc //ID生成器
}

// NewEventMgr 创建一个新的 EventMgr 实例，并应用可选配置
func NewEventMgr(opts ...option) *EventMgr {
	result := &EventMgr{}
	result.EventList = make(map[EventTypeEnum]map[uint64]OnEventChanged)

	result.getID = getidf
	for _, opt := range opts {
		opt(result)
	}
	return result
}

// Destroy 销毁事件管理器，释放资源
func (this *EventMgr) Destroy() {
	this.EventList = nil
}

// Prepare 恢复准备，重新初始化事件列表
func (this *EventMgr) Prepare() {
	this.EventList = make(map[EventTypeEnum]map[uint64]OnEventChanged)
}

// Recycle 回收事件管理器，释放事件列表资源
func (this *EventMgr) Recycle() {
	this.EventList = nil
}

// AddEvent 添加一个事件监听器，返回分配的事件ID
func (this *EventMgr) AddEvent(evtType EventTypeEnum, f OnEventChanged) uint64 {
	if f == nil {
		return 0
	}
	id := this.getID()
	if this.EventList[evtType] == nil {
		this.EventList[evtType] = make(map[uint64]OnEventChanged)
	}
	this.EventList[evtType][id] = f
	return id
}

// RemoveEvent 移除指定类型和ID的事件监听器
func (this *EventMgr) RemoveEvent(evtType EventTypeEnum, id uint64) {
	if this.EventList[evtType] != nil {
		delete(this.EventList[evtType], id)
	}
}

// TriggerEvent 触发指定类型事件，并传递可选参数
// 触发事件时，会调用所有注册的事件处理函数，包括默认事件类型
func (this *EventMgr) TriggerEvent(evtType EventTypeEnum, argsopts ...optionArgs) {
	if this.EventList[evtType] == nil {
		return
	}
	args := &EventArgs{}
	args.EventType = evtType
	for _, opt := range argsopts {
		opt(args)
	}
	for _, f := range this.EventList[evtType] {
		f(args)
	}
	for _, f := range this.EventList[EventType_Default] {
		f(args)
	}
}

// IsExistByKey 判断指定类型和ID的事件监听器是否存在
func (this *EventMgr) IsExistByKey(evtType EventTypeEnum, id uint64) bool {
	if this.EventList[evtType] == nil {
		return false
	}
	_, exist := this.EventList[evtType][id]
	return exist
}
